package com.dh.blog.auth;

import java.lang.reflect.Method;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Calendar;
import java.util.Date;
import java.util.Properties;
import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import sun.tools.tree.ThisExpression;

import com.dh.blog.auth.annotations.Authority;
import com.dh.blog.auth.annotations.Session;
import com.dh.blog.utils.Encrypter;
import com.dh.blog.utils.TokenUtils;
import com.ewei.web.common.exception.MessageRuntimeException;
import com.ewei.web.common.http.HttpUtils;
import com.ewei.web.common.json.JsonUtils;
import com.ewei.web.common.response.ResponseVO;
import com.mchange.v2.c3p0.impl.AuthMaskingProperties;
/**
 * 无状态授权认证拦截器
 * @author David
 *
 */
public abstract class StatelessAuthInterceptor extends HandlerInterceptorAdapter{
	@Resource
	protected Properties config;
	private static final Logger logger = LogManager.getLogger(StatelessAuthInterceptor.class);
	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		AuthToken authToken = null;
		boolean accessable = false;
		if(!(accessable = isAccessable(handler))){
			authToken = authToken(request,response);
			if(null != authToken){
				boolean isLogin = isLogin(authToken);
				if(isLogin){
					accessable = true;
				}
			}
			if(HttpUtils.isAjax(request)){
				response.getWriter()
					.write(JsonUtils.toJson(new ResponseVO().setDatas(""), ResponseVO.class));
			}else{
				
			}
		}
		System.out.println(this.getClass().getCanonicalName()+":-->"+request.getRequestURI());
		if(accessable){
			updateSession(request, response, authToken);
		}
		return accessable;
	}
	
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		if(handler instanceof HandlerMethod){
			HandlerMethod handlerMethod = (HandlerMethod)handler;
			Method method = handlerMethod.getMethod();
			if(method.isAnnotationPresent(Session.class)){//是扫描方法上的保存会话标识
				saveSession(request, response);
			}
		}
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		//这里一定要释放ThreadLocal资源
		AuthUtils.removeIndentify();
	}
	/**
	 * 获得身份令牌(以身份令牌判断登陆状态)
	 * @param request
	 * @param response
	 * @return
	 */
	public AuthToken authToken(HttpServletRequest request,
			HttpServletResponse response) throws Exception{
		AuthToken authToken = null;
		Cookie cookie = HttpUtils.getCookie(request, getCookieName());
		if(null != cookie){
			String value = URLDecoder.decode(cookie.getValue(),"UTF-8");
			String[] array = null;
			if(null != value &&
					null != (array = value.split(","))&&array.length == 2){
				authToken = new AuthToken(array[0],array[1]);
			}
		}
		return authToken;
	}
	/**
	 * 扫描类或方法上的认证标识
	 * @param handler
	 * @return
	 */
	protected boolean isAccessable(Object handler){
		if(handler instanceof HandlerMethod){
			HandlerMethod handlerMethod = (HandlerMethod)handler;
			Class<?> type = handlerMethod.getBeanType();
			if(type.isAnnotationPresent(Authority.class)){
				return false;
			}
			Method method = handlerMethod.getMethod();
			if(method.isAnnotationPresent(Authority.class)){
				return false;
			}
		}
		return true;
	}
	/**
	 * 是否登陆
	 * @param request
	 * @param response
	 * @return
	 */
	protected boolean isLogin(AuthToken authToken){
		String tokenValue = authToken.getTokenValue();
		String authValue = authToken.getAuthValue();
		try {
			return TokenUtils.validate(tokenValue, authValue);
		} catch (Exception e) {
			logger.info(e);
			throw new MessageRuntimeException(e);
		}
	}
	/**
	 * 更新会话（更新身份认证令牌）
	 * @param request
	 * @param response
	 */
	protected void updateSession(HttpServletRequest request,
			HttpServletResponse response,AuthToken authToken)throws Exception{
		if(null == authToken){//原令牌为空，从请求中找
			authToken = authToken(request, response);
		}
		if(null != authToken){
			String identify = authToken.getIdentify();
			if(null == identify){
				identify = TokenUtils
						.getUserFromAuth(Encrypter.base64Decoder(authToken.getAuthValue()));
				AuthUtils.addIdentify(identify);//添加身份信息
			}
			Date date = Calendar.getInstance().getTime();
			String authValue = TokenUtils.generateAuth(identify,date);
			String tokenValue = TokenUtils.generateToken(identify,date);
			Cookie cookie = new Cookie(getCookieName(),
					URLEncoder.encode(authValue+","+tokenValue,"UTF-8"));
			cookie.setPath("/");
			response.addCookie(cookie);
		}
	}
	/**
	 * 保存会话（生成身份认证令牌）
	 * @param request
	 * @param response
	 */
	protected void saveSession(HttpServletRequest request,
				HttpServletResponse response) throws Exception{
		String identify = AuthUtils.getIdentifyAndRemove();//获得身份信息
		if(null != identify){
			Date date = Calendar.getInstance().getTime();
			String authValue = TokenUtils.generateAuth(identify,date);
			String tokenValue = TokenUtils.generateToken(identify,date);
			Cookie cookie = new Cookie(getCookieName(),
					URLEncoder.encode(authValue+","+tokenValue,"UTF-8"));
			cookie.setPath("/");
			response.addCookie(cookie);
		}
	}
	/**
	 * 获得cookie名字
	 */
	protected abstract String getCookieName();
	/**
	 * 获得角色
	 * @param request
	 * @param response
	 * @return
	 */
	protected abstract String[] getRoles(AuthToken authToken);
	/**
	 * 获得权限
	 * @param authToken
	 * @return
	 */
	protected abstract String[] getPermissions(AuthToken authToken);
}
